import { Ball } from "./_ball";
import { Block } from "./block";
import { Player } from "./player";

import bg from "./bg.jpg";

export class GameCore {
  width: number;
  height: number;
  canvas: HTMLCanvasElement;
  ctx: CanvasRenderingContext2D;
  keydowns: { [key: string]: boolean } = {};
  actions: { [key: string]: () => void } = {};
  blocks: Block[] = [];
  status: "start" | "end" = "start";
  ball: Ball;
  paddle: Player;
  levels = [
    [
      [50, 50],
      [150, 120],
    ],
    [
      [50, 0],
      [100, 100],
      [150, 130],
    ],
    [
      [50, 30],
      [100, 100],
      [200, 100],
    ],
  ];
  constructor(root: Element) {
    const { width, height } = root.getBoundingClientRect();

    this.width = width;
    this.height = height;

    this.ball = new Ball(this.width, this.height);
    this.paddle = new Player(this.width, this.height);

    this.canvas = document.createElement("canvas");
    root.appendChild(this.canvas);

    this.canvas.width = this.width;
    this.canvas.height = this.height;

    this.canvas.style.border = "1px solid";
    this.ctx = this.canvas.getContext("2d")!;

    window.addEventListener("keydown", this.onKeyDown);
    window.addEventListener("keyup", this.onKeyUp);

    this.registerAction("a", () => {
      this.paddle.moveLeft();
    });
    this.registerAction("d", () => {
      this.paddle.moveRight();
    });
    this.registerAction("w", () => {
      this.paddle.moveTop();
    });
    this.registerAction("s", () => {
      this.paddle.moveBottom();
    });

    this.play();
  }

  onKeyDown = (evt: KeyboardEvent) => {
    this.keydowns[evt.key] = true;
    if (evt.key === "r") {
      this.ball.suspend();
    }
    const n = parseInt(evt.key);
    if (!isNaN(n)) {
      this.switchLevel(n);
    }
  };

  bg?: HTMLImageElement;

  play = async () => {
    const image = new Image();
    image.src = bg;
    image.onload = () => {
      this.bg = image;
    };

    this.frameLoop();
  };

  drawBg = () => {
    if (this.bg) {
      this.ctx.drawImage(this.bg, 0, 0);
    }
  };

  switchLevel = (n: number) => {
    n -= 1;
    this.blocks = [];
    this.levels[n]?.forEach((l) => {
      const block = new Block(l[0], l[1]);
      this.blocks.push(block);
    });
  };

  onKeyUp = (evt: KeyboardEvent) => {
    this.keydowns[evt.key] = false;
  };

  close() {
    this.status = "end";
    window.removeEventListener("keydown", this.onKeyDown);
    window.removeEventListener("keyup", this.onKeyUp);
  }
  registerAction(key: string, callback: () => void) {
    this.actions[key] = callback;
  }

  frameLoop = () => {
    //执行按键action
    for (let key in this.keydowns) {
      if (this.keydowns[key]) {
        if (this.actions[key]) this.actions[key]();
      }
    }
    this.update();
    this.clearCanvas();
    this.drawCanvas();
    if (this.status === "end") return;
    //next frame
    requestAnimationFrame(this.frameLoop);
  };

  update() {
    this.ball.move();
    if (this.paddle.collide(this.ball)) {
      //如果上一帧也是被碰撞，下一帧就不改变球的运动方向
      if (!this.ball.lastBump) {
        this.ball.reboundY();
      }
      this.ball.lastBump = true;
    } else {
      this.ball.lastBump = false;
    }
    this.blocks.forEach((block) => {
      if (block.collide(this.ball)) {
        this.ball.reboundY();
        block.kill();
      }
    });
    this.blocks = this.blocks.filter((b) => b.alive);
  }
  drawCanvas() {
    this.drawBg();
    this.drawPaddle();
    this.drawBall();
    this.drawBlock();
  }
  drawBlock() {
    this.blocks.forEach((b) => {
      this.ctx.fillStyle = "black";
      this.ctx.fillRect(b.x, b.y, b.width, b.height);
    });
  }
  drawPaddle() {
    this.ctx.fillStyle = "black";
    this.ctx.fillRect(
      this.paddle.x,
      this.paddle.y,
      this.paddle.width,
      this.paddle.height
    );
  }
  drawBall() {
    this.ctx.fillStyle = "red";
    this.ctx.fillRect(
      this.ball.x,
      this.ball.y,
      this.ball.width,
      this.ball.height
    );
  }
  //擦除画板
  clearCanvas() {
    this.ctx.clearRect(0, 0, this.width, this.height);
  }
}
